package cate.game.pvp.eliterace.handler;

import cate.common.table.d.GDFight;
import cate.game.framework.common.compress.CompressedContent;
import cate.game.framework.common.compress.PlaySideCompressHelper;
import cate.game.play.part.PlaySide;
import cate.game.play.proce.play.PlayPO;
import cate.game.pvp.eliterace.data.EliteRacePs;
import cate.game.pvp.eliterace.data.EliteRaceRecord;
import easy.java.practice.errorcode.EcResult;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

import static cate.game.pvp.eliterace.util.EliteRaceSpecUtils.getVideoLevel;
import static cate.game.pvp.eliterace.util.EliteRaceSpecUtils.isTrial;

@Slf4j
public class BothEliteRaceFightOperation implements EliteRaceFightOperation {

    private final BiFunction<PlaySide, PlaySide, EcResult<PlayPO>> fightFunction;
    private final BiConsumer<PlayPO, EliteRaceRecord> playPOConsumer;
    private final Function<Integer, Long> pointsExcelQueryFunction;

    public BothEliteRaceFightOperation(BiFunction<PlaySide, PlaySide, EcResult<PlayPO>> fightFunction,
                                       BiConsumer<PlayPO, EliteRaceRecord> playPOConsumer,
                                       Function<Integer, Long> pointsExcelQueryFunction) {
        this.fightFunction = fightFunction;
        this.playPOConsumer = playPOConsumer;
        this.pointsExcelQueryFunction = pointsExcelQueryFunction;
    }

    @Override
    public EcResult<Long> startFight(EliteRaceRecord record, EliteRacePs psA, EliteRacePs psB, Consumer<PlayPO> consumer) {
        EcResult<Long> r = new EcResult<>();
        PlaySide sideA = null, sideB = null;
        if (Objects.nonNull(psA)) {
            record.setPsA(psA.getCpsList().size() - 1);
            CompressedContent cc = psA.getCpsList().get(record.getPsA());
            EcResult<PlaySide> ps_r = PlaySideCompressHelper.uncompressEc(cc);
            if (!ps_r.ok()) {
                log.error("解压玩家阵容出现错误 {}", psA.getUid());
                return r.fail();
            }
            sideA = ps_r.data;
        }

        if (Objects.nonNull(psB)) {
            record.setPsB(psB.getCpsList().size() - 1);
            CompressedContent last = psB.getCpsList().getLast();
            EcResult<PlaySide> ps_r = PlaySideCompressHelper.uncompressEc(last);
            if (!ps_r.ok()) {
                log.error("解压玩家阵容出现错误 {}", psB.getUid());
                return r.fail();
            }
            sideB = ps_r.data;
        }

        if (Objects.isNull(sideA) || Objects.isNull(sideB)) {
            byte winner = Objects.nonNull(sideA) ? GDFight.Team.A : GDFight.Team.B;
            record.setWinner(winner);
            long powerA = Objects.nonNull(sideA) ? sideA.getTotalPower() : 0L;
            long powerB = Objects.nonNull(sideB) ? sideB.getTotalPower() : 0L;
            r.data = Math.abs(powerA - powerB);
            handleResult(record, psA, psB, winner, !isTrial(record.getSpec()));
            return r.success();
        }

        EcResult<PlayPO> pr = fightFunction.apply(sideA, sideB);
        if (!pr.ok()) {
            log.error("战斗出现错误!");
            return r.fail();
        }

        PlayPO playPO = pr.data;
        playPO.story.level = getVideoLevel(record.getSpec());
        record.setWinner(playPO.winner);
//        record.setReplayId(playPO.uid);
        record.setRecordTime(playPO.startTime);
        handleResult(record, psA, psB, playPO.winner, !isTrial(record.getSpec()));

        consumer.accept(playPO);
        playPOConsumer.accept(playPO, record);

        r.data = Math.abs(sideA.getTotalPower() - sideB.getTotalPower());

        return r.success();
    }

    private void handleResult(EliteRaceRecord record, EliteRacePs psA, EliteRacePs psB, byte winner, boolean count) {
        if (winner == GDFight.Team.A) {
            record.setAPoints(psA.getOpponent().getPoints());
            psA.getOpponent().win(count, pointsExcelQueryFunction.apply(getVideoLevel(record.getSpec())));
            record.setAPointsChanged(psA.getOpponent().getPoints() - record.getAPoints());
            if (Objects.nonNull(psB)) {
                record.setBPoints(psB.getOpponent().getPoints());
                psB.getOpponent().loose(count);
                record.setBPointsChanged(psB.getOpponent().getPoints() - record.getBPoints());
            }
        } else if (!isTrial(record.getSpec())) {
            record.setBPoints(psB.getOpponent().getPoints());
            psB.getOpponent().win(count, pointsExcelQueryFunction.apply(getVideoLevel(record.getSpec())));
            record.setBPointsChanged(psB.getOpponent().getPoints() - record.getBPoints());
            if (Objects.nonNull(psA)) {
                record.setAPoints(psA.getOpponent().getPoints());
                psA.getOpponent().loose(count);
                record.setAPointsChanged(psA.getOpponent().getPoints() - record.getAPoints());
            }
        }
    }
}
